
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "fp_log.h"
#include "fp_algorithm.h"
#include "fp_task.h"
#include "fingerprint.h"
#include "fp_timer.h"
#include "fp_led.h"
#include "fp_template.h"
#include "app_action.h"

u8 lowpower_flag = 0;

void bfxx_fingerprint_task();
void check_recovery_mode(void);

static struct fp_protocol_info g_fp_protocol_info = {0};

struct fp_protocol_info* fp_info(void)
{
    return &g_fp_protocol_info;
}

void protoEn(unsigned mode)
{
    struct fp_protocol_info* info = fp_info();
    if (mode) {
        info->fingerdown = 1; /* 手指按压 */
        info->mode = 1;
        info->begin = fp_timer_get();
        info->phase_fingeroff = 0;
        fp_do_checkfingeroff(); /* 判断离手 */
    } else {
        info->mode = 0;
        fp_do_idle();
        info->recovery_mode = 0;
        info->p1 = 0;
        info->p2 = 0;
        info->data = 0;
        info->phase = 0;
        info->phase_time = 0;
        info->lowpower_cnt = 0;
        info->phase_fingeroff = 0;
    }
}

unsigned int isProtoEn(void)
{
    struct fp_protocol_info* info = fp_info();
    return info->mode;
}

void taskrun_lock(void)
{
    struct fp_protocol_info* info = fp_info();
    info->taskrun_lock = 1;
}

void taskrun_unlock(void)
{
    struct fp_protocol_info* info = fp_info();
    update_poweroff_timer();
    info->taskrun_lock = 0;
}

int is_taskrun_lock(void)
{
    struct fp_protocol_info* info = fp_info();
    return info->taskrun_lock;
}

void measure_lock(int identify_id)
{
    struct fp_protocol_info* info = fp_info();
    info->identify_id = identify_id;
    info->identify_valid = 1;
    if (identify_id == 0 || identify_id == 1)
        info->identify_vip = 1;
    else
        info->identify_vip = 0;

    protoEn(1);
}

int measure_tryunlock(void)
{
    struct fp_protocol_info* info = fp_info();
    int p1 = info->p1;
    // int p2 = info->p2;
    // int data = info->data;
    int phase = info->phase;
    int lock = 0;

    if (p1 == TASK_VERIFY_LED)
        measure_phase(); /* Try to wait for MEASURE_PHASE7 to check figneroff */
    else
        protoEn(0);

    if (phase == 0)
        lock = 0;
    else
        lock = 1;

    return lock;
}

void measure_unlock(void)
{
    protoEn(0);
}

int micro_sw_test_get(void);

#define LOWPOWER_WARNING_TICK_TIME 300
#define LOWPOWER_WARNING_TICK_CNT  3

int micro_sw_test_start_state = 0;
int finger_busy_flag = 0;

void measure_phase(void)
{
    struct fp_protocol_info* info = fp_info();
    int p1 = info->p1;
    int p2 = info->p2;
    int data = info->data;
    int phase = info->phase;

    if (p1 == TASK_VERIFY_LED && p2 == TASK_VERIFY_COMPLETED_LED) {
        switch (phase) {
            case MEASURE_PHASE0: { /* idle */
                /* Nothing TODO */
            } break;
            case MEASURE_PHASE1: { /* low power check light on */
                if (lowpower_flag) {
                    uint32_t t = fp_timer_get();
                    uint32_t diff = t - info->phase_time;

                    if ((diff > LOWPOWER_WARNING_TICK_TIME) &&
                        (info->lowpower_cnt == LOWPOWER_WARNING_TICK_CNT)) {
                        bf_print_d("phase1-1");
                        info->phase = MEASURE_PHASE3;
                        info->phase_time = 0;
                        info->lowpower_cnt = 0;
                        return;
                    }

                    if ((info->lowpower_cnt == 0) ||
                        ((diff > LOWPOWER_WARNING_TICK_TIME) && (info->lowpower_cnt > 0))) {
                        bf_print_d("phase1-2");
                        fp_led_ctrl(FP_LED1, LED_ON);
                        // fp_led_ctrl(FP_LED2, LED_ON);
                        info->phase = MEASURE_PHASE2;
                        info->phase_time = fp_timer_get();
                    }

                } else {
                    if(finger_busy_flag){
                        bf_print_d("phase1-busy");
                        return;
                    }
                    else{
                            bf_print_d("phase1-3");
                            info->phase = MEASURE_PHASE3;
                            info->phase_time = 0;
                            info->lowpower_cnt = 0;
                            finger_busy_flag = 1;
                    }
                }
            } break;
            case MEASURE_PHASE2: { /* low power check light off */
                if (lowpower_flag) {
                    uint32_t t = fp_timer_get();
                    uint32_t diff = t - info->phase_time;
                    if (diff > LOWPOWER_WARNING_TICK_TIME) {
                        bf_print_d("phase2-1");
                        fp_led_ctrl(FP_LED1, LED_OFF);
                        fp_led_ctrl(FP_LED2, LED_OFF);
                        info->lowpower_cnt++;
                        if (info->lowpower_cnt <= LOWPOWER_WARNING_TICK_CNT) {
                            info->phase = MEASURE_PHASE1;
                            info->phase_time = fp_timer_get();
                        }
                    }
                } else {
                    bf_print_d("phase2-2");
                    info->phase = MEASURE_PHASE3;
                    info->phase_time = 0;
                    info->lowpower_cnt = 0;
                }
            } break;
            case MEASURE_PHASE3: { /* verify light on and moto on */
                if (data) {        /* 正确手指 */
                    bf_print_d("phase3-1");
                    fp_led_ctrl(FP_LED1, LED_OFF);  // 红灯 熄灭
                    fp_led_ctrl(FP_LED2, LED_ON);   // 绿灯 亮起
                    /* 打开杯盖 */
                    fp_moto(MOTO_FORWARD);
                    info->phase_time = fp_timer_get();
                    info->phase = MEASURE_PHASE4;
                    micro_sw_test_start_state = micro_sw_test_get();

#if 1 /* 自学习 */
                    unsigned int nr = btl_storage_get_enroll_template_count();
                    TIME_MEASURE_INIT(update);
                    TIME_MEASURE_UPDATE(update);
                    /* update template */
                    if (nr > 0) {
                        int retval = btl_ai_update(info->identify_id,
                                                   BSUT_UPDATE_TEMPLATE | BSUT_UPDATE_OTHER_INFO);
                        bf_print_d("IID update:%d", retval);
                    }
                    TIME_MEASURE_DIFF_PRINT(update, "update");
#endif
                } else { /* 错误手指 */
                    bf_print_d("phase3-2");
                    fp_led_ctrl(FP_LED1, LED_ON);
                    fp_led_ctrl(FP_LED2, LED_OFF);
                    info->phase_time = fp_timer_get();
                    info->phase = MEASURE_PHASE4;
                }

            } break;
            case MEASURE_PHASE4: { /* verify light off and moto off */
                uint32_t t = fp_timer_get();
                uint32_t diff = t - info->phase_time;
//                if (diff > 250)
                if ((micro_sw_test_start_state == 1 && micro_sw_test_get() == 0) ||
                    (diff > 270))
                {
                    if (data) { /* 正确手指 */
                        bf_print_d("phase4-1");
                        fp_led_ctrl(FP_LED1, LED_OFF);
                        fp_led_ctrl(FP_LED2, LED_OFF);
                          fp_timer_delay_ms(10);       // 20250831,增加逻辑修改，马达压到限位卡开关后，继续转几十ms

                        fp_moto(MOTO_STOP);
                        info->phase = MEASURE_PHASE5;
                        info->phase_time = fp_timer_get();
                    } else { /* 错误手指 */
                        bf_print_d("phase4-2");
                        fp_led_ctrl(FP_LED1, LED_OFF);
                        fp_led_ctrl(FP_LED2, LED_OFF);
                        info->phase = MEASURE_PHASE7;
                        info->phase_time = fp_timer_get();
                    }
                }
            } break;
            case MEASURE_PHASE5: {
                uint32_t t = fp_timer_get();
                uint32_t diff = t - info->phase_time;
                if (diff > 800) {
                    bf_print_d("phase5-1");
                    fp_moto(MOTO_REVERSE);
                    info->phase = MEASURE_PHASE6;
                    info->phase_time = fp_timer_get();
                }
            } break;
            case MEASURE_PHASE6: {
                uint32_t t = fp_timer_get();
                uint32_t diff = t - info->phase_time;
                if (diff > 150) {
                    bf_print_d("phase6-1");
                    fp_moto(MOTO_STOP);
                    info->phase = MEASURE_PHASE7;
                    info->phase_time = fp_timer_get();
                }
            } break;
            case MEASURE_PHASE7: {
                if (info->phase_fingeroff) {
                    bf_print_d("phase7-1");
                    protoEn(0);
                }
                finger_busy_flag = 0;
            } break;
            default:
                break;
        }
    }
}

unsigned int measure_diff(void)
{
    struct fp_protocol_info* info = fp_info();
    return fp_timer_diff_of(info->begin);
}

u8 ble_init_flag = 0;//0未初始化 ，1 ble已初始化完成，2蓝牙已连接
void bfxx_protocol_task(void)
{
    struct fp_protocol_info* info = fp_info();

    clr_wdt();

    if (!isProtoEn()) {
        return;
    }

    measure_phase();

    unsigned int diff = measure_diff();

    // bf_print_d("info->fingerdown: %d, diff: %u, vip: %d, invalid: %d", info->fingerdown, diff,
    //            info->identify_vip, info->identify_valid);

    /* 手在按压中 */
    if (info->fingerdown) {
        if (diff > FP_ENROLL_TIMEOUT) {
            info->identify_valid = 0;
        }

        if (info->identify_vip) {
            unsigned int nr = btl_storage_get_enroll_template_count();
            /* 判断录入 */
            if (diff > FP_ENROLL_TIMEOUT && diff < FP_REMOVE_TIMEOUT) {
                /* 小于最大手指个数，支持进入录入模式 */
                if (nr < TEMPLATE_MAX_FINGERS) {
                    if (info->fingerdown <= LIGHTON_TODO_ENROLL) {
                        bf_print_d("TODO Enroll");
                        info->fingerdown = LIGHTON_TODO_REMOVE;
                        /* 右灯常亮 */
                        notify(TASK_ENROLL_LED, TASK_ENROLL_TODO_LED, 0);
                    }
                }
            } else if (diff > FP_REMOVE_TIMEOUT && diff < FP_MANAGER_TIMEOUT) { /* 判断删除 */
                if (info->fingerdown <= LIGHTON_TODO_REMOVE) {
                    info->fingerdown = LIGHTON_TODO_RECOVERY;
                    /* 左灯常亮 */
                    if (nr > 0) {
                        bf_print_d("TODO Remove");
                        notify(TASK_REMOVE_LED, TASK_REMOVE_TODO_LED, 0);
                    } else {
                        /* 左右灯全灭，取消管理者模式 */
                        notify(TASK_EXITVIP_LED, 0, 0);
                    }
                }
            } else if (diff > FP_MANAGER_TIMEOUT) {
                /* 左右灯全灭，取消管理者模式 */
                notify(TASK_EXITVIP_LED, 0, 0);
            }
        }

        if (diff > FP_RECOVERY_TIMEOUT && !info->recovery_mode) {
            if (info->fingerdown <= LIGHTON_TODO_RECOVERY) {
                info->fingerdown = LIGHTON_TODO_EXIT;
                if (info->identify_id < 0) { /* 错误手指长按进入 Recovery 模式*/
                    bf_print_d("TODO Recovery");
                    info->recovery_mode = 1;
                    info->recovery_id_cnt = 0;
                    info->recovery_cnt1 = 0;
                    info->recovery_cnt2 = 0;
                    info->recovery_stage = 0;
                    memset(info->recovery_id, 0, sizeof(info->recovery_id));
                    notify(TASK_RECOVERY_LED, TASK_RECOVERY_TODO_LED, 0);
                }
            }
        }
    }

    /* 手指离开 */
    if (!info->fingerdown) {
        if (info->recovery_mode) {
            return check_recovery_mode();
        } else {
            // bf_print_d("finger off");
            if (info->phase_fingeroff == 0)
                info->phase_fingeroff_time = fp_timer_get();

            info->phase_fingeroff = 1;

            int unlock = measure_tryunlock();
            if (!unlock)
                return;

            // unsigned int fingeroff_diff = fp_timer_diff_of(info->phase_fingeroff_time);
            // if (fingeroff_diff > 1000)
            //     return;

            if (info->identify_vip) {
                unsigned int nr = btl_storage_get_enroll_template_count();
                if (diff > FP_ENROLL_TIMEOUT && diff < FP_REMOVE_TIMEOUT) {
                    if (nr < TEMPLATE_MAX_FINGERS) {
                        fp_do_enroll();
                    }
                } else if (diff > FP_REMOVE_TIMEOUT && diff < FP_MANAGER_TIMEOUT) {
                    if (nr > 0) {
                        fp_do_Identifyremove();
                    }
                }
            }
        }
    }
}
u8 led_falg = 0;

/*******************************
 * 1. 充电时红灯闪烁
*************************/
void charge_led_hander()
{
#if 1 /* only to debug */

    if (is_taskrun_lock())
        return;

    if (led_falg == 0) {
        fp_led_ctrl(FP_LED1, LED_ON);
        led_falg = 1;
    } else {
        fp_led_ctrl(FP_LED1, LED_OFF);
        led_falg = 0;
    }
    fp_led_ctrl(FP_LED2, LED_OFF);
#endif
}
void charge_led_off()
{
#if 1
    fp_led_ctrl(FP_LED1, LED_OFF);
    fp_led_ctrl(FP_LED2, LED_OFF);
#endif
}

/*******************************
 * 1. 充满电时绿灯常亮
*************************/
void charge_led_full()
{
#if 1
    fp_led_ctrl(FP_LED1, LED_OFF);
    fp_led_ctrl(FP_LED2, LED_ON);
#endif
}

void notify(int p1, int p2, int data)
{
    struct fp_protocol_info* info = fp_info();
    struct intent it;
    switch (p1) {
        case TASK_VERIFY_LED: {
            if (p2 == TASK_VERIFY_COMPLETED_LED) {
                info->p1 = p1;
                info->p2 = p2;
                info->data = data;
                if (data) {
                    info->phase = MEASURE_PHASE1;
                } else {
                    // info->phase = MEASURE_PHASE3;
                    info->phase = MEASURE_PHASE1;
                }
            }
        } break;
        case TASK_ENROLL_LED: {
            /* 录入过程中 */
            if (p2 == TASK_ENROLL_TODO_LED) { /* 进入录入模式 */
                /* 右灯常亮 */
                fp_led_ctrl(FP_LED1, LED_OFF);
                fp_led_ctrl(FP_LED2, LED_ON);
            } else if (p2 == TASK_ENROLL_ADDED_LED) {
                if (data) { /* 采集成功 */
                    fp_led_ctrl(FP_LED2, LED_ON);
                    fp_timer_delay_ms(500);
                    fp_led_ctrl(FP_LED2, LED_OFF);
                } else { /* 采集失败 */
                    fp_led_ctrl(FP_LED1, LED_ON);
                    fp_timer_delay_ms(500);
                    fp_led_ctrl(FP_LED1, LED_OFF);
                }

            } else if (p2 == TASK_ENROLL_COMPLETED_LED) {
                /* 录入成功 */
               fp_led_ctrl(FP_LED1, LED_OFF);
                fp_led_ctrl(FP_LED2, LED_ON);           // 绿灯闪烁3次
                fp_timer_delay_ms(500);
                fp_led_ctrl(FP_LED2, LED_OFF);          // refresh 1, 这里刚成成功，不是第一次闪烁
                fp_timer_delay_ms(500);

                fp_led_ctrl(FP_LED2, LED_ON);         // refresh 1 ，第一次闪烁
                fp_timer_delay_ms(500);
                fp_led_ctrl(FP_LED2, LED_OFF);
                fp_timer_delay_ms(500);

                  fp_led_ctrl(FP_LED2, LED_ON);       // refresh 2，第二次闪烁
                fp_timer_delay_ms(500);
                fp_led_ctrl(FP_LED2, LED_OFF);
                fp_timer_delay_ms(500);

                fp_led_ctrl(FP_LED2, LED_ON);       // refresh 3，第三次闪烁
                fp_timer_delay_ms(500);

                fp_led_ctrl(FP_LED1, LED_OFF);
                fp_led_ctrl(FP_LED2, LED_OFF);
            }
        } break;
        case TASK_REMOVE_LED: {
            if (p2 == TASK_REMOVE_TODO_LED) { /* 进入删除模式 */
                fp_led_ctrl(FP_LED1, LED_ON);
                fp_led_ctrl(FP_LED2, LED_OFF);
                //  = 3;
            } else if (p2 == TASK_REMOVE_COMPLETED_LED) {
                if (data) { /* 删除成功 */
                    fp_led_ctrl(FP_LED1, LED_OFF);
                    fp_led_ctrl(FP_LED2, LED_ON);
                    fp_timer_delay_ms(2000);
                    fp_led_ctrl(FP_LED1, LED_OFF);
                    fp_led_ctrl(FP_LED2, LED_OFF);
                } else { /* 删除失败 */
                    fp_led_ctrl(FP_LED1, LED_OFF);
                    fp_timer_delay_ms(100);
                    fp_do_Identifyremove();
                    fp_led_ctrl(FP_LED1, LED_ON);
                    fp_timer_delay_ms(1000);
                    fp_led_ctrl(FP_LED1, LED_OFF);
                }
                //  = 0;
            }
        } break;
        case TASK_RESET_LED:
        case TASK_EXITVIP_LED: {
            fp_led_ctrl(FP_LED1, LED_OFF);
            fp_led_ctrl(FP_LED2, LED_OFF);
            fp_timer_delay_ms(500);
        } break;
        case TASK_RECOVERY_LED: {
            if (p2 == TASK_RECOVERY_TODO_LED) {
                fp_led_ctrl(FP_LED1, LED_ON);
                fp_led_ctrl(FP_LED2, LED_OFF);
            } else if (p2 == TASK_RECOVERY_COMPLETED_LED) {
                if (data) { /* Recovery 成功*/
                    fp_led_ctrl(FP_LED1, LED_ON);
                    fp_led_ctrl(FP_LED2, LED_ON);
                    fp_timer_delay_ms(1000);
                    fp_led_ctrl(FP_LED1, LED_OFF);
                    fp_led_ctrl(FP_LED2, LED_OFF);
                } else { /* Recovery 失败 */
                    fp_led_ctrl(FP_LED1, LED_OFF);
                    fp_led_ctrl(FP_LED2, LED_ON);
                    fp_timer_delay_ms(1000);
                    fp_led_ctrl(FP_LED1, LED_OFF);
                    fp_led_ctrl(FP_LED2, LED_OFF);
                }
            } else if (p2 == TASK_RECOVERY_CHECK_LED) { /* Recovery check */
                fp_led_ctrl(FP_LED1, LED_ON);
                fp_led_ctrl(FP_LED2, LED_ON);
                fp_timer_delay_ms(200);
                fp_led_ctrl(FP_LED1, LED_OFF);
                fp_led_ctrl(FP_LED2, LED_OFF);
            } else if (p2 == TASK_RECOVERY_INPUT_LED) {
                fp_led_ctrl(FP_LED1, LED_OFF);
                fp_led_ctrl(FP_LED2, LED_OFF);
                fp_timer_delay_ms(200);
                fp_led_ctrl(FP_LED1, LED_ON);
                fp_led_ctrl(FP_LED2, LED_OFF);
            } else if (p2 == TASK_RECOVERY_TO_STAGE2) {
                fp_led_ctrl(FP_LED1, LED_OFF);
                fp_led_ctrl(FP_LED2, LED_ON);
                fp_timer_delay_ms(200);
                fp_led_ctrl(FP_LED1, LED_ON);
                fp_led_ctrl(FP_LED2, LED_OFF);
            }
        }break;
        default:
            break;
    }
}

void poweroff_timer_init(unsigned short poweroff_timer_id)
{
    struct fp_protocol_info* info = fp_info();
    info->poweroff_timer_id = poweroff_timer_id;
}
void update_poweroff_timer(void)
{
    struct fp_protocol_info* info = fp_info();
    sys_timer_re_run(info->poweroff_timer_id);
}

void check_recovery_mode(void)
{
    struct fp_protocol_info* info = fp_info();
    unsigned int current = fp_timer_get();
    unsigned int exit_diff = current - info->recovery_lasttime;

    if (exit_diff > RECOVERY_TIMEOUT) {
        if (info->recovery_stage == 0) {
            /* 第一阶段匹配成功 */
            info->recovery_cnt1 = info->recovery_id_cnt;
            info->recovery_stage = 1; /* 开启第二阶段检查 */
            info->recovery_lasttime = current;
            notify(TASK_RECOVERY_LED, TASK_RECOVERY_TO_STAGE2, 0);
        } else if (info->recovery_stage == 1) {
            info->recovery_cnt2 = info->recovery_id_cnt - info->recovery_cnt1;
            unsigned int fingeroff_diff = current - info->recovery_lasttime;
            bf_print_d("recovery: stage2, id1: %u, id2: %u", info->recovery_cnt1,
                       info->recovery_cnt2);
            if (info->recovery_cnt1 == RECOVERY_ID1 && info->recovery_cnt2 == RECOVERY_ID2) {
                btl_storage_remove_all_template();
                notify(TASK_RECOVERY_LED, TASK_RECOVERY_COMPLETED_LED, 1); /* 成功 */
            } else {
                notify(TASK_RECOVERY_LED, TASK_RECOVERY_COMPLETED_LED, 0);
            }

            measure_unlock();
        }
    }

    return;
}
